/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.editor.model;
import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;

import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;

import offset.nodes.client.editor.view.SchemaRenderer;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

public class SchemaTree  {
	DefaultMutableTreeNode root = null;
	
    public SchemaTree(InputStream in, JTree tree) throws Exception {
        createTree( in, tree);
        tree.setCellRenderer(new SchemaRenderer());
    }
    
    public void createTree(InputStream in, JTree tree) throws IOException, SAXException, ParserConfigurationException {
    	SchemaHandler handler = new SchemaHandler();
    	
 		XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
		reader.setContentHandler(handler);
		reader.parse(new InputSource(in));		
		
        root = handler.getRoot();
        ((DefaultTreeModel)tree.getModel()).setRoot(root);
    }
    
    public DefaultMutableTreeNode getRoot() {
    	return root;
    }
    
    public class SchemaElement {
    	String name;
    	String path;
    	int maxOccurs = 1;
    	int minOccurs = 1;
    	
    	public static final int UNBOUNDED = -1;
    	
		public SchemaElement(String name) {
			super();
			this.name = name;
		}
		
		public int getMaxOccurs() {
			return maxOccurs;
		}
		
		public void setMaxOccurs(int maxOccurs) {
			this.maxOccurs = maxOccurs;
		}
		
		public int getMinOccurs() {
			return minOccurs;
		}
		
		public void setMinOccurs(int minOccurs) {
			this.minOccurs = minOccurs;
		}
		
		public String getName() {
			return name;
		}
		
		public void setName(String name) {
			this.name = name;
		}
		
		public String getPath() {
			return path;
		}

		public void setPath(String path) {
			this.path = path;
		}

		public String toString() {
			return name;
		}
    }
    
    class SchemaHandler extends DummyContentHandler implements ContentHandler {
    	protected Stack current = new Stack();
    	DefaultMutableTreeNode root = null;

		public void endElement(String uri, String localName, String qName) throws SAXException {
			if ( getName(localName, qName).endsWith(":element"))
				current.pop();			
		}

		public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
			String name = getName(localName, qName);
			if ( !name.endsWith(":element") )
				return;
			
			SchemaElement element = new SchemaElement(name);
			for( int i=0; i<atts.getLength(); i++) {
				if ( getName(atts.getLocalName(i), atts.getQName(i)).equals( "minOccurs") )
					element.setMinOccurs(Integer.parseInt(atts.getValue(i)));
				else if ( getName(atts.getLocalName(i), atts.getQName(i)).equals( "maxOccurs")) {
					if ( atts.getValue(i).equals( "unbounded"))
						element.setMaxOccurs(SchemaElement.UNBOUNDED);
					else
						element.setMaxOccurs(Integer.parseInt(atts.getValue(i)));
				}
				else if ( getName(atts.getLocalName(i), atts.getQName(i)).equals( "name")) 
					element.setName(atts.getValue(i));
			}
			
			DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(element);
			if ( current.size() > 0) {
				DefaultMutableTreeNode parent = (DefaultMutableTreeNode) current.peek();
				parent.add(newNode);
			}
			
			current.push( newNode );			
			element.setPath( getPath(current));
			if ( root == null)
				root = newNode;
		}

		protected String getName(String localName,String qName) {
			return qName;
		}
		
		protected String getPath( Stack path ) {
			StringBuffer buf = new StringBuffer();
			for( int i=0; i<path.size(); i++) {
				buf.append("/");
				SchemaElement e = (SchemaElement) ((DefaultMutableTreeNode)path.get(i)).getUserObject();
				buf.append(e.getName());
			}
			
			return buf.toString();
		}
		
		public DefaultMutableTreeNode getRoot() {
			return root;
		}
        
    }
    
}
